﻿namespace LMT.Communication.Ipc
{
    using System;
    using System.IO.Pipes;
    using System.Threading;

    public class NamedPipeClient
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data">The data.</param>
        public delegate void ReceiveDataHandler(byte[] data);

        /// <summary>
        /// Occurs when [receive data event].
        /// </summary>
        public event ReceiveDataHandler ReceiveDataEvent;

        /// <summary>
        /// 
        /// </summary>
        public delegate void ConnectionHandler();

        /// <summary>
        /// Occurs when [disconnect from server].
        /// </summary>
        public event ConnectionHandler DisconnectFromServer;

        /// <summary>
        /// 
        /// </summary>
        private string pipeName;

        /// <summary>
        /// 
        /// </summary>
        private NamedPipeClientStream clientPipe;

        /// <summary>
        /// Initializes a new instance of the <see cref="TcpClient"/> class.
        /// </summary>
        /// <param name="pipeName">Name of the pipe.</param>
        public NamedPipeClient(string pipeName)
        {
            if (PipeHelper.Instance == null)
            {
                PipeHelper.CreateInstance(null);
            }

            this.pipeName = pipeName;
        }

        /// <summary>
        /// Starts this instance.
        /// </summary>
        public void Start()
        {
            this.clientPipe = new NamedPipeClientStream(".", this.pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);

            this.clientPipe.Connect();

            Thread waitForServer = new Thread(delegate()
            {
                this.WaitForServer();
            });
            waitForServer.IsBackground = true;
            waitForServer.Start();
        }

        /// <summary>
        /// Stops this instance.
        /// </summary>
        public void Stop()
        {
            if (this.clientPipe != null)
            {
                this.clientPipe.Close();
                this.clientPipe.Dispose();
            }

            this.clientPipe = null;
        }

        /// <summary>
        /// Sends the data to server.
        /// </summary>
        /// <param name="data">The data.</param>
        public void Send(byte[] data)
        {
            PipeHelper.Instance.SendData(this.clientPipe, data);
        }

        /// <summary>
        /// Sends the data to server.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Send(string message)
        {
            PipeHelper.Instance.SendData(this.clientPipe, message);
        }

        /// <summary>
        /// Waits for server.
        /// </summary>
        private void WaitForServer()
        {
            try
            {
                while (this.clientPipe.IsConnected)
                {
                    byte[] data = PipeHelper.Instance.ReadData(this.clientPipe);
                    if (data != null && this.ReceiveDataEvent != null)
                    {
                        this.ReceiveDataEvent(data);
                    }
                }
            }
            catch (Exception ex)
            {
                this.ProcessConnectionException(ex);
            }
        }

        /// <summary>
        /// Fires the disconnect server.
        /// </summary>
        /// <param name="ex">The ex.</param>
        private void ProcessConnectionException(Exception ex)
        {
            //SocketException se = ex as SocketException;
            //if (se != null)
            //{
            //    if (se.ErrorCode == 10054)
            //    {
            //        this.IsConnected = false;
            //    }
            //}
            //else if ((ex as IOException) != null)
            //{
            //    if (ex.InnerException != null)
            //    {
            //        se = ex.InnerException as SocketException;
            //        if (se != null)
            //        {
            //            if (se.ErrorCode == 10054)
            //            {
            //                this.IsConnected = false;
            //            }
            //        }
            //    }
            //}

            if (!this.clientPipe.IsConnected)
            {
                this.Stop();
            }

            if (this.DisconnectFromServer != null)
            {
                this.DisconnectFromServer();
            }
        }
    }
}
